package cn.ycc1.functionlibrary.streams;

/**
 * Reducing a Stream
 * @author ycc
 * @date 2025/3/7
 */
public class ReducingStream {

    /**
     * Calling a Terminal Operation on a Stream
     * So far you read in this tutorial that reducing a stream consists of aggregating the elements of that stream in a way
     * that looks like what is done in the SQL language. In the examples you ran, you also collected the elements of the streams
     * you built in a list, using the collect(Collectors.toList()) pattern. All these operations are called terminal operations
     * in the Stream API and consists in reducing your stream.
     *
     * There are two things you need to remember when calling a terminal operation on a stream.
     *
     * A stream without a terminal operation does not process any data. If you spot such a stream in your application,
     * it is most probably a bug.
     * A given stream instance can only have one intermediate or terminal operation call. You cannot reuse a stream;
     * if you try to do that, you will get an IllegalStateException.
     */

    /**
     * Using a Binary Operator to Reduce a Stream
     * There are three overloads of the reduce() method defined in the Stream interface. They all take a BinaryOperator object
     * as an argument. Let us examine how this binary operator is used.
     *
     * Let us take a example. Suppose you have a list of integers, and you need to compute the sum of these integers. You can
     * write the following code to compute this sum, using a classic for loop pattern.
     */

    /**
     * Choosing a Binary Operator That Can Be Used in Parallel
     * There are two caveats you need to understand though. Let us the first one here and the second one in the next section.
     *
     * The first one is that a stream can be computed in parallel. This point will be covered in more detail later in this
     * tutorial, but we need to talk about it now because it has an impact on this binary operator.
     *
     * Here is how parallelism is implemented in the Stream API. Your source of data is split in two parts, each part processed
     * separately. Each process is the same process as the one you just saw, which uses your binary operator. Then, when each
     * part is processed, the two partial results are merged with that same binary operator.
     */

    /**
     * Managing Binary Operators That Do Have Any Identity Element
     * The second one is a consequence of this associativity property your binary operator should have.
     *
     * This associativity property is imposed by the fact that the way your data is divided should not impact the result of your
     * computation. If you split a set A into two subsets B and C, then reducing A should give you the same result as reducing
     * the reduction of B and the reduction of C.
     *
     * You can write the previous property to the more general following expression:
     *
     * A = B ⋃ C ⇒ Red(A) = Red(Red(B), Red(C))
     *
     * It turns out that it leads to another consequence. Suppose things are not going well, and that B is in fact empty.
     * In that case, C = A. The previous expression becomes the following:
     *
     * Red(A) = Red(Red(∅), Red(A))
     *
     * This is true if and only if the reduction of the empty set (∅) is the identity element of the reduction operation.
     *
     * This is a general property in data processing: the reduction of the empty set is the identity element of the reduction
     * operation.
     *
     * This is really a problem in data processing, and especially in parallel data processing, because some very classic
     * reduction binary operators do not have an identity element, namely MIN and MAX. The minimum element of an empty set
     * is not defined because the MIN operation does not have an identity element.
     *
     * This problem has to be addressed in the Stream API because you may have to deal with empty streams. You saw patterns
     * to create empty streams, and it is quite easy to see that a filter() call can filter out all the data your stream is
     * processing, thus returning a stream that will have nothing to process.
     *
     * The choice that has been made in the Stream API is the following. A reduction for which the identity element is
     * unknown (either non-existing, either non-provided) returns an instance of the Optional class. We will cover this class
     * in more details later in this tutorial. What you need to know at this point is that this Optional class is a wrapper
     * class that can be empty. Every time you call a terminal operation on a stream that has no known identity element,
     * the Stream API will wrap the result in that object. If the stream you processed was empty, then this optional will
     * also be empty, and it will be up to you and your application to decide how to handle the situation.
     */

    /**
     * Exploring the Reduction Methods of the Stream API
     * As we mentioned earlier, the Stream API has three overloads of the reduce() methods, which we can now present in details.
     *
     * Reducing with an Identity Element
     * The first one takes an identity element and an instance of BinaryOperator. Because the first argument you provide
     * is known to be the identity element of the binary operator, the implementation may use that to simplify the computation.
     * Instead of taking the first two elements of the stream to start the process, it does not take any and starts with this
     * identity element. The algorithm used has the following form.
     */

    /**
     * Reducing with an Identity Element
     * The second overload of the reduce() method only takes an instance of BinaryOperator with no identity element.
     * As expected, it returns an Optional object, wrapping the result of the reduction. The simplest thing you can do with
     * an optional is just to open it and see if there is anything in it.
     *
     * Fusing Mapping and Reduction in one Method
     * The third one is a little more complex. It combines an internal mapping and a reduction with several parameters.
     */


}
